package cn.edu.gdut.deepcode.service.impl;

import cn.edu.gdut.deepcode.annotation.CanvasIdCheckPoint;
import cn.edu.gdut.deepcode.component.SimpleGlobalLock;
import cn.edu.gdut.deepcode.domain.po.CanvasSnapshot;
import cn.edu.gdut.deepcode.domain.po.Result;
import cn.edu.gdut.deepcode.mapper.CanvasSnapshotMapper;
import cn.edu.gdut.deepcode.service.ICanvasSnapshotService;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.List;

import static cn.edu.gdut.deepcode.constant.CacheConstant.*;
import static cn.edu.gdut.deepcode.constant.ReqRespConstant.COMMON_SUCCESSFUL_MSG;

/**
 * <p>
 * 画布快照表 服务实现类
 * </p>
 *
 * @author author
 * @since 2025-04-11
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class CanvasSnapshotServiceImpl extends ServiceImpl<CanvasSnapshotMapper, CanvasSnapshot> implements ICanvasSnapshotService {

    private final StringRedisTemplate redisTemplate;
    private final SimpleGlobalLock globalLock;

    @Override
    @CanvasIdCheckPoint
    public Result<?> directSaveSnapshot(Long canvasId, String canvasData) {
        // 创建快照对象
        CanvasSnapshot canvasSnapshot = new CanvasSnapshot();
        // 设置其他数据
        canvasSnapshot
                .setCanvasId(canvasId)
                .setCanvasData(canvasData)
                .setOffset(-1L);// 直接存储时偏移量为-1
        save(canvasSnapshot);
        clearCache(canvasId);
        return Result.success();
    }



    @Override
    @CanvasIdCheckPoint
    public Result<String> getSnapshotById(Long canvasId) {
        // 查询缓存
        String snapshotCacheKey = CANVAS_SNAPSHOT_CACHE_KEY_PREFIX + canvasId;
        String snapshotCache = redisTemplate.opsForValue().get(snapshotCacheKey);
        // 缓存不为null,返回缓存
        if (snapshotCache != null) {
            return Result.success(COMMON_SUCCESSFUL_MSG, snapshotCache);
        }
        // 缓存为空加全局锁
        String lockKey = CANVAS_SNAPSHOT_LOCK_KEY_PREFIX + canvasId;
        long threadId = Thread.currentThread().getId();
        boolean locked = globalLock.tryLock(
                lockKey,
                threadId,
                COMMON_LOCK_EXPIRE_TIME,
                COMMON_LOCK_EXPIRE_TIME_UNIT
        );
        if (!locked){
            // 加锁失败返回null值
            return Result.success();
        }
        try {
            // 加锁成功查数据库
            Page<CanvasSnapshot> page = new Page<>(1, 1);
            page.addOrder(OrderItem.desc("id"));
            lambdaQuery()
                    .select(CanvasSnapshot::getCanvasData)
                    .eq(CanvasSnapshot::getCanvasId, canvasId)
                    .page(page);
            List<CanvasSnapshot> records = page.getRecords();
            if (CollUtil.isEmpty(records)) {
//                log.warn(CD_EI_1, List.of(UserContext.getUser(), canvasId, records));
                records = Collections.emptyList();
            }

            // 数据库有信息则缓存正常信息,无信息则缓存特殊值(防止缓存穿透)
            String snapshotCacheValue = records.size() > 0 ?
                    records.get(0).getCanvasData() : "";
            redisTemplate.opsForValue().set(
                    snapshotCacheKey,
                    snapshotCacheValue,
                    COMMON_EXPIRE_TIME,
                    COMMON_EXPIRE_TIME_UNIT
            );
            // 返回数据
            return Result.success(COMMON_SUCCESSFUL_MSG, snapshotCacheValue);
        } finally {
            // 解锁
            globalLock.unlock(lockKey, threadId);
        }
    }

    @Override
    public void deleteSnapshotById(Long canvasId) {
        lambdaUpdate()
                .eq(CanvasSnapshot::getCanvasId,canvasId)
                .remove();
        clearCache(canvasId);
    }


    public void clearCache(Long canvasId) {
        // 清空缓存
        redisTemplate.delete(CANVAS_SNAPSHOT_CACHE_KEY_PREFIX+ canvasId);
    }

    public void genSnapshot(Long canvasId) {

    }
}
